﻿using MyHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace weighing
{
    /// <summary>
    /// 海康微视
    /// </summary>
    public class HKCameraHelper : ICamera
    {
        public static string message = string.Empty;
        public static Int32 m_lPort = -1;
        public Int32 currCameraId = -1;
        public static uint iLastErr;
        public bool isInitSDK;
        public bool isLogin = false;
        public bool isPreviewSuccess = false;
        public int m_lRealHandle = -1;
        public PictureBox mPictureBox;
        public CHCNetSDK.REALDATACALLBACK RealData = null;
        public static IntPtr m_ptrRealHandle;

        public bool InitSDK()
        {
            return CHCNetSDK.NET_DVR_Init();
        }
        /// <summary>
        /// login Camera
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="userName"></param>
        /// <param name="pwd"></param>
        /// <returns>currcamera id </returns>
        public int LoginV30(string ip, int port, string userName, string pwd, ref CHCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo)
        {
            return CHCNetSDK.NET_DVR_Login_V30(ip, port, userName, pwd, ref deviceInfo);
        }
        // 返回-1表示登录失败，其他值表示返回的用户ID值
        public int Login(string ip, int port, string userName, string pwd, ref CHCNetSDK.NET_DVR_DEVICEINFO_V40 deviceInfo)
        {
            CHCNetSDK.NET_DVR_USER_LOGIN_INFO userInfo = new CHCNetSDK.NET_DVR_USER_LOGIN_INFO();

            //设备IP地址或者域名
            byte[] byIP = Encoding.Default.GetBytes(ip);
            userInfo.sDeviceAddress = new byte[129];
            byIP.CopyTo(userInfo.sDeviceAddress, 0);

            //设备用户名
            byte[] byUserName = Encoding.Default.GetBytes(userName);
            userInfo.sUserName = new byte[64];
            byUserName.CopyTo(userInfo.sUserName, 0);
            userInfo.wPort = ushort.Parse(port.ToString());

            //设备密码
            byte[] byPassword = Encoding.Default.GetBytes(pwd);
            userInfo.sPassword = new byte[64];
            byPassword.CopyTo(userInfo.sPassword, 0);
            userInfo.bUseAsynLogin = false;
            int res = CHCNetSDK.NET_DVR_Login_V40(ref userInfo, ref deviceInfo);
            return res;
        }

        public bool LoginOut(int loginhandle)
        {
            try
            {
                return CHCNetSDK.NET_DVR_Logout(loginhandle);
            }
            catch (Exception)
            {
            }
            return false;
        }

        /// <summary>
        /// 预览
        /// </summary>
        /// <param name="pbHandle"> picthure Box Handle</param>
        /// <param name="loginHandle">登录摄像头成功返回的 user id Or handle</param>
        /// <param name="channel">设备通道</param>
        /// <param name="errorCode">错误状态码</param>
        /// <returns>int 预览成功后的 句丙 </returns>
        public int Preview(IntPtr pbHandle, int loginHandle, int channel, out uint errorCode)
        {
            errorCode = 0;
            try
            {
                var lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO
                {
                    hPlayWnd = pbHandle,//预览窗口
                    lChannel = channel,//预览的设备通道
                    dwStreamType = 1,//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                    dwLinkMode = 0,//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                    bBlocked = false, //0- 非阻塞取流，1- 阻塞取流
                    dwDisplayBufNum = 20 //播放库播放缓冲区最大缓冲帧数
                };

                // RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数               
                //打开预览 Start live view 
                int res = -100;
                res = CHCNetSDK.NET_DVR_RealPlay_V40(loginHandle, ref lpPreviewInfo, null, new IntPtr());
                if (res == -1)
                {
                    errorCode = CHCNetSDK.NET_DVR_GetLastError();
                }
                return res;
            }
            catch (Exception ex)
            {
                Log.Error("预览出错：" + ex.Message);
                return -1;
            }

        }
        /// <summary>
        /// 预览
        /// </summary>
        /// <param name="img"></param>
        /// <param name="loginHandle"></param>
        /// <param name="channel"></param>
        /// <returns>int 预览成功后的 句丙 </returns>
        public static int Preview(ref System.Windows.Controls.Image img, int loginHandle, int channel)
        {
            try
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.hPlayWnd = InptrHelper.GetControlHandle(img);//预览窗口
                lpPreviewInfo.lChannel = channel;//预te览的设备通道
                lpPreviewInfo.dwStreamType = 1;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                lpPreviewInfo.bBlocked = false; //0- 非阻塞取流，1- 阻塞取流
                lpPreviewInfo.dwDisplayBufNum = 20; //播放库播放缓冲区最大缓冲帧数

                // RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数               
                //打开预览 Start live view 
                int handle = CHCNetSDK.NET_DVR_RealPlay_V40(loginHandle, ref lpPreviewInfo, null, new IntPtr());
                return handle;
            }
            catch (Exception)
            {
                return -1;
            }
        }

        /// <summary>
        ////预览 实时流回调函数
        /// </summary>
        /// <param name="img"></param>
        /// <param name="lChannel"></param>
        /// <param name="currCameraId"></param>
        /// <param name="streamType"></param>
        /// <returns></returns>
        public static bool PreviewCallBack(ref PictureBox pb, int lChannel, int currCameraId, int streamType = 0)
        {
            try
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.hPlayWnd = pb.Handle;//预览窗口
                lpPreviewInfo.lChannel = lChannel;//预te览的设备通道
                lpPreviewInfo.dwStreamType = (uint)streamType;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                lpPreviewInfo.bBlocked = false; //0- 非阻塞取流，1- 阻塞取流
                lpPreviewInfo.dwDisplayBufNum = 20; //播放库播放缓冲区最大缓冲帧数

                var RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数               
                //打开预览
                CHCNetSDK.NET_DVR_RealPlay_V40(currCameraId, ref lpPreviewInfo, RealData, new IntPtr());
                return true;
            }
            catch (Exception)
            {
                return false;
            }

        }
        public static void RealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser)
        {
            //下面数据处理建议使用委托的方式
            // MyDebugInfo AlarmInfo = new MyDebugInfo(DebugInfo);
            switch (dwDataType)
            {
                case CHCNetSDK.NET_DVR_SYSHEAD:     // sys head
                    if (dwBufSize > 0)
                    {
                        if (m_lPort >= 0)
                        {
                            return; //同一路码流不需要多次调用开流接口
                        }

                        //获取播放句柄 Get the port to play
                        if (!PlayCtrl.PlayM4_GetPort(ref m_lPort))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            message = "PlayM4_GetPort failed, error code= " + iLastErr;
                            // this.mPictureBox.BeginInvoke(AlarmInfo, message);
                            break;
                        }

                        //设置流播放模式 Set the stream mode: real-time stream mode
                        if (!PlayCtrl.PlayM4_SetStreamOpenMode(m_lPort, PlayCtrl.STREAME_REALTIME))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            message = "Set STREAME_REALTIME mode failed, error code= " + iLastErr;
                            //this.mPictureBox.BeginInvoke(AlarmInfo, message);
                        }

                        //打开码流，送入头数据 Open stream
                        if (!PlayCtrl.PlayM4_OpenStream(m_lPort, pBuffer, dwBufSize, 2 * 1024 * 1024))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            message = "PlayM4_OpenStream failed, error code= " + iLastErr;
                            //this.mPictureBox.BeginInvoke(AlarmInfo, message);
                            break;
                        }


                        //设置显示缓冲区个数 Set the display buffer number
                        if (!PlayCtrl.PlayM4_SetDisplayBuf(m_lPort, 15))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            message = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;
                            // this.mPictureBox.BeginInvoke(AlarmInfo, message);
                        }

                        //设置显示模式 Set the display mode
                        if (!PlayCtrl.PlayM4_SetOverlayMode(m_lPort, 0, 0/* COLORREF(0)*/)) //play off screen 
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            message = "PlayM4_SetOverlayMode failed, error code= " + iLastErr;
                            // this.mPictureBox.BeginInvoke(AlarmInfo, message);
                        }

                        //设置解码回调函数，获取解码后音视频原始数据 Set callback function of decoded data                      
                        if (!PlayCtrl.PlayM4_SetDecCallBackEx(m_lPort, new PlayCtrl.DECCBFUN(DecCallbackFUN), IntPtr.Zero, 0))
                        {
                            //  this.mPictureBox.BeginInvoke(AlarmInfo, "PlayM4_SetDisplayCallBack fail");
                        }

                        //开始解码 Start to play                       
                        if (!PlayCtrl.PlayM4_Play(m_lPort, m_ptrRealHandle))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            message = "PlayM4_Play failed, error code= " + iLastErr;
                            // this.mPictureBox.BeginInvoke(AlarmInfo, message);
                            //System.Threading.Thread.Sleep(2);
                            break;
                        }
                    }
                    break;
                case CHCNetSDK.NET_DVR_STREAMDATA:     // video stream data
                    if (dwBufSize > 0 && m_lPort != -1)
                    {
                        for (int i = 0; i < 999; i++)
                        {
                            //送入码流数据进行解码 Input the stream data to decode
                            if (!PlayCtrl.PlayM4_InputData(m_lPort, pBuffer, dwBufSize))
                            {
                                iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                                message = "PlayM4_InputData failed, error code= " + iLastErr;
                                // System.Threading.Thread.Sleep(2);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    break;
                default:
                    if (dwBufSize > 0 && m_lPort != -1)
                    {
                        //送入其他数据 Input the other data
                        for (int i = 0; i < 999; i++)
                        {
                            if (!PlayCtrl.PlayM4_InputData(m_lPort, pBuffer, dwBufSize))
                            {
                                iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                                message = "PlayM4_InputData failed, error code= " + iLastErr;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    break;
            }
        }
        //解码回调函数
        private static void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
        {
            // 将pBuf解码后视频输入写入文件中（解码后YUV数据量极大，尤其是高清码流，不建议在回调函数中处理）
            if (pFrameInfo.nType == 3)
            {

            }
        }


        /// <summary>
        /// captureBmp
        /// </summary>
        /// <param name="filePathName">图片保存路径和文件名</param>
        /// <param name="lRealHandle ">通NET_DVR_RealPlay或NET_DVR_RealPlay_V30的返回值 </param>
        /// <returns></returns>
        public static bool CaptureBmp(int lRealHandle, string filePathName)
        {
            //BMP抓图 Capture a BMP picture
            try
            {
                CHCNetSDK.NET_DVR_SetCapturePictureMode();
            }
            catch (Exception e)
            {
                Log.Error("BMP抓图 Capture a BMP picture CHCNetSDK.NET_DVR_SetCapturePictureMode failure:" + e.Message);
            }
            return CHCNetSDK.NET_DVR_CapturePicture(lRealHandle, filePathName);
        }

        /// <summary>
        /// 停止预览
        /// </summary>
        /// <param name="handle"> play handle or login handle</param>
        /// <returns></returns>
        public bool StopPreview(int handle)
        {
            try
            {
                return CHCNetSDK.NET_DVR_StopRealPlay(handle);
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 截图
        /// </summary>
        /// <param name="loginHandle">登录的摄像头 句丙</param>
        /// <param name="filePathName">图片保存路径和文件名</param>
        /// <param name="lChannel">通道号(海康专用)</param>
        /// <param name="quality">压缩图片质量</param>
        public bool CaptureJpeg(int loginHandle, string filePathName, int lChannel, int quality)
        {
            CHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA
            {
                wPicQuality = 0, //图像质量 Image quality 0-最好，1-较好，2-一般 
                wPicSize = 0xff //抓图分辨率 Picture size: 2- 4CIF，0xff- Auto(使用当前码流分辨率)，抓图分辨率需要设备支持，更多取值请参考SDK文档
            };
            //JPEG抓图 Capture a JPEG picture
            try
            {
                return CHCNetSDK.NET_DVR_CaptureJPEGPicture(loginHandle, lChannel, ref lpJpegPara, filePathName);
            }
            catch (Exception e)
            {
                Console.WriteLine(filePathName + " 抓图失败：" + e.Message + " err no:" + CHCNetSDK.NET_DVR_GetLastError());
                return false;
            }
        }
        /// <summary>
        /// 其它品牌使用
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="userName"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int Login(string ip, int port, string userName, string pwd)
        {
            throw new NotImplementedException("非 海康微视 品牌的实现");
        }
    }
}
